package ar.com.photo_admin.services;

import java.util.ArrayList;
import java.util.List;

import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import ar.com.photo_admin.R;
import ar.com.photo_admin.domain.Album;
import ar.com.photo_admin.domain.BaseEntity;
import ar.com.photo_admin.domain.Event;
import ar.com.photo_admin.domain.Token;
import ar.com.photo_admin.exception.UnreachableNetworkException;
import ar.com.photo_admin.persistence.TokenDAO;
import ar.com.photo_admin.services.ServiceLayerImpl.TokenOperationResponse.TokenOperationCode;

public class ServiceLayerImpl implements ServiceLayer {

	private RestTemplate rest;

	private Context context;

	private TokenDAO tokenDao;
	
	private String serverUrl;
	
	private static final int TIME_OUT = 30;

	public ServiceLayerImpl(Context context) {

		this.context = context;
		this.rest = new RestTemplate();
		this.tokenDao = new TokenDAO(context);
		
		rest.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
		
		SimpleClientHttpRequestFactory factory = ((SimpleClientHttpRequestFactory) rest.getRequestFactory());
		factory.setReadTimeout(TIME_OUT * 1000);
		
		setServerUrl();
	}
	
	private void setServerUrl() {
		SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
		
		String domainUrl = preferences.getString("domain_url", "");
		
		if (!domainUrl.startsWith("http://"))
			domainUrl = "http://" + domainUrl;
		
		if (!domainUrl.endsWith("/"))
			domainUrl = domainUrl.concat("/");
			
		serverUrl = domainUrl + "remoteApi/";
	}

	@Override
	public Album getAlbum(String token, Long albumId) {

		String url = serverUrl + "album?albumId=" + albumId + "&token=" + token;
		Album album = null;

		try {
			Log.i("getAlbum: ", url);
			album = rest.getForObject(url, Album.class);

		} catch (ResourceAccessException e) {
			Log.e("Network is unreachable: ", "getAlbum");
			throw new UnreachableNetworkException();
		} catch (Exception e) {
			Log.e("Error in service: ", "getAlbum");
			e.printStackTrace();
		}
		
		return album;
	}

	@Override
	public Event getEvent(String token) {

		String url = serverUrl + "event?token=" + token;
		Event event = null;

		try {
			Log.i("getEvent: ", url);
			event = rest.getForObject(url, Event.class);
			event.setToken(token);

		} catch (ResourceAccessException e) {
			Log.e("Network is unreachable: ", "getEvent");
			throw new UnreachableNetworkException();
		} catch (Exception e) {
			Log.e("Error in service: ", "getEvent");
			e.printStackTrace();
		}

		return event;
	}

	@Override
	public List<Event> getEvents() {
		
		List<Event> events = new ArrayList<Event>();
		
		try {
			tokenDao.open();
			
			List<Token> allTokens = tokenDao.getAllTokens();
			
			for (Token token : allTokens) {
				Event event = getEvent(token.getToken());
				
				if (event != null && event.getStatus() != BaseEntity.STATUS_ERROR)
					events.add(event);
			}
			
			tokenDao.close();
			
		} catch (UnreachableNetworkException e) {
			Log.e("Network is unreachable: ", "getEvents");
			throw e;
		} catch (Exception e){
			Log.e("Error in service: ", "getEvents");
			e.printStackTrace();
		}		

		return events;
	}

	public static class TokenOperationResponse {
		
		public enum TokenOperationCode {
			INVALID,
			ALREADY_SAVED,
			ADDED,
			DELETED,
			DATABASE_ERROR,
			CONNECTION_PROBLEM;
		}
		
		public TokenOperationCode code;
		public String message;		
	}
	
	@Override
	public TokenOperationResponse addToken(String token) {

		Token newToken = new Token();
		newToken.setToken(token);

		TokenOperationResponse result = new TokenOperationResponse();

		try {
			Event event = getEvent(token);
			
			if (event == null) {
				result.code = TokenOperationCode.CONNECTION_PROBLEM;
				return result;
			}		
			
			newToken.setEventId(event.getId());
			
			if (event.getStatus() == BaseEntity.STATUS_ERROR) {
				result.code = TokenOperationResponse.TokenOperationCode.INVALID;
				result.message = context.getString(R.string.invalid_token);
			}
			else {
			
				tokenDao.open();
				List<Token> allTokens = tokenDao.getAllTokens();

				/*
				 * Check if the token is already in the db.
				 */
				if (allTokens.contains(newToken)) {
					result.code = TokenOperationResponse.TokenOperationCode.ALREADY_SAVED;
					result.message = context.getString(R.string.already_saved_token);
				} else {
					/*
					 * Check if any of the tokens has the event that it's trying to
					 * be added.
					 */
					// Long eventId = event.getId();
					
					result.code = TokenOperationResponse.TokenOperationCode.ADDED;
					result.message = context.getString(R.string.added_token, event.getName());
					
					/* for (Token dbToken : allTokens) {
						if (dbToken.getEventId().equals(eventId)) {
							result = "El evento " + event.getName() + " ha sido actualizado";
							break;
						}
					}*/
					
					tokenDao.saveOrUpdateToken(newToken);
				}

				tokenDao.close();
			}
		} catch (Exception e) {
			result.code = TokenOperationResponse.TokenOperationCode.DATABASE_ERROR;
			result.message = context.getString(R.string.database_error);
		}

		return result;
	}
	
	@Override
	public TokenOperationResponse deleteAllTokens() {
		
		TokenOperationResponse result = new TokenOperationResponse();
		
		try {
			tokenDao.open();
			tokenDao.deleteAllTokens();
			tokenDao.close();
			
			result.code = TokenOperationResponse.TokenOperationCode.DELETED;
			result.message = context.getString(R.string.clear_events_success);
			
		} catch (Exception e) {
			result.code = TokenOperationResponse.TokenOperationCode.DATABASE_ERROR;
			result.message = context.getString(R.string.clear_events_fail);
		}
		
		return result;
	}
}
